#ifndef _CLASSDEFINITION_
#define _CLASSDEFINITION_

#include "TreeNode.h"
#include "FieldDeclaration.h"
#include "MethodDefinition.h"

#include <vector>

using namespace std;

class ClassDefinition: public TreeNode
{
public:
    ClassDefinition(string iClassName,
                    vector<FieldDeclaration*> iFields,
                    vector<MethodDefinition*> iMethods,
                    vector<string> iParentClassNames);

    virtual ~ClassDefinition();
    virtual void Accept(GeneralVisitor*);

    void ResolveVariables();
    void ResolveFunctionCalls(set<FunctionDefinition*>& iAllFunctions);
    void ResolveClassConstructions(set<ClassDefinition*>& iAllClasses);
    void CheckExpressionTypes();

    string GetClassName() { return this->fClassName; }

    // Provede kontrolu deklarovanych metod.
    // Podobne jako u globalnich funkci kontroluje, jestli neexistuje vice metod se stejnym nazvem a poctem parametru.
    void CheckMethods();

    // Vrati vsechny konstruktory tridy (tj. metody, ktere se jmenuji stejne jako trida).
    vector<MethodDefinition*> GetConstructors();

    // Zjisti, zda existuje field se zadanym jmenem.
    bool FieldExists(string iFieldName);

    // Zjisti, zda existuje metoda se zadanym jmenem a poctem parametru.
    bool MethodExists(string iMethodName, int iParamCount);

    // Vrati definici metody se zadanym jmenem a poctem parametru.
    MethodDefinition* GetMethodDefinition(string iMethodName, unsigned int iParamCount);

    // Vyresi dedicnost. Najde rodicovske tridy a zkopiruje si k sobe odkazy na jejich metody a fieldy.
    void ResolveInheritance(set<ClassDefinition*>& iAllClasses);

    bool IsInheritanceResolved() { return fInheritanceResolved; }

    // Vrati seznam vsech fieldu, vlastnich i zdedenych.
    vector<FieldDeclaration*> GetAllFields();

    // Vrati seznam vsech metod, vlastnich i zdedenych.
    vector<MethodDefinition*> GetAllMethods();

private:
    string fClassName;

    // Toto jsou fieldy, ktere definuju primo ja.
    vector<FieldDeclaration*> fFields;

    // Toto jsou metody, ktere definuju primo ja.
    vector<MethodDefinition*> fMethods;

    // Toto jsou fieldy, ktere jsem zdedil od vsech svych rodicu.
    vector<FieldDeclaration*> fInheritedFields;

    // Toto jsou metody, ktere jsem zdedil od vsech svych rodicu.
    vector<MethodDefinition*> fInheritedMethods;

    vector<string> fParentClassNames;

    // Odkazy na moje prime predky.
    vector<ClassDefinition*> fDirectParents;

    bool fInheritanceResolved;

    // Na zaklade fParentClassNames a seznamu trid naplni fDirectParents.
    void SetDirectParents(set<ClassDefinition*>& iAllClasses);

    // Zpracuje metody zdedene od jednoho predka.
    void ProcessInheritedMethods(vector<MethodDefinition*>& iMethods);

    // Zpracuje fieldy zdedene od jednoho predka.
    void ProcessInheritedFields(vector<FieldDeclaration*>& iFields);
};

#endif
